import uuid

from ckeditor_uploader.fields import RichTextUploadingField  # 富文本V4
from django.conf import settings
from django.contrib.auth.models import AbstractUser, Group, Permission, UserManager
from django.contrib.auth.models import AbstractUser, PermissionsMixin
# from django_ckeditor_5.fields import CKEditor5Field  # 富文本V5
from django.contrib.sessions.base_session import AbstractBaseSession
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator, MaxValueValidator, FileExtensionValidator
from django.db import models
from django.db import transaction
from django.db.models import F
from django.db.models import JSONField  # Django 3.2及以上版本
from django.db.models import Q
from django.utils import timezone
from django.utils.deconstruct import deconstructible
# 安装 django-redis（核心库）
# pip install django-redis
# 安装 redis-py（Python 的 Redis 客户端，必选依赖）
# pip install redis
# 配置settings.py
from django_redis import get_redis_connection
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFill
from mptt.fields import TreeManyToManyField  # 引入MPTT优化字段,Category表使用
from mptt.models import MPTTModel, TreeForeignKey

from utils.wechat import wechat_check_sign  # 自定义模块路径检查


# ############################# 相关函数或类:  ####################################
@deconstructible  # 关键：允许Django序列化该类
class DatedUploadPath:
    def __init__(self, base_path):
        self.base_path = base_path

    def __call__(self, instance, filename):
        # 生成随机文件名 + 日期路径
        ext = filename.split('.')[-1]
        uuid_name = uuid.uuid4().hex
        date_path = timezone.localtime().strftime("%Y/%m/%d")  # localtime强制转换为上海时间
        return f"{self.base_path}/{date_path}/{uuid_name}.{ext}"


# ##############################################################################
class UserInfo(AbstractUser):
    """用户表"""
    # 默认字段：username, password, email, first_name, last_name, is_staff, is_active, is_superuser, last_login, date_joined
    # 重写username字段并设置verbose_name
    username = models.CharField('用户名', max_length=150, unique=True, error_messages={'unique': '用户名已被占用'})
    # 重写email字段并设置verbose_name
    email = models.EmailField('邮箱', unique=True, error_messages={'unique': '邮箱已被注册'})
    token = models.CharField(max_length=255, blank=True, null=True, verbose_name="用户Token")
    openid = models.CharField(max_length=255, blank=True, null=True, verbose_name="用户OpenID")
    session_key = models.CharField(max_length=255, blank=True, null=True, verbose_name="会话密钥")
    phone = models.CharField(max_length=15, verbose_name="手机号", unique=True)  # 手机号必填且唯一
    avatar = models.ImageField(upload_to=DatedUploadPath('avatar'), null=True, blank=True,
                               verbose_name='头像路径')  # 自动按日期分目录存储
    address = models.TextField(blank=True, null=True, verbose_name="收货地址")  # 收货地址
    nickname = models.CharField(max_length=128, verbose_name="微信昵称", blank=True, null=True)
    last_online = models.DateTimeField(auto_now=True, verbose_name="最后在线时间")
    # 自定义权限字段
    groups = models.ManyToManyField(
        Group,
        verbose_name="用户组",
        blank=True,
        help_text="用户所属的组。",
        related_name="UserInfo_set",  # 避免与默认 User 模型冲突
        related_query_name="userinfo",
    )
    user_permissions = models.ManyToManyField(
        Permission,
        verbose_name="用户权限",
        blank=True,
        help_text="用户拥有的特定权限。",
        related_name="UserInfo_set",  # 避免与默认 User 模型冲突
        related_query_name="userinfo",
    )

    # 显式声明管理器（非必需但建议）
    objects = UserManager()

    class Meta:
        verbose_name = "用户"
        verbose_name_plural = "用户"
        db_table = 'jewelry_userinfo'  # 确保表名与实际一致
        # ordering = ['id']
        permissions = [  # codename 需与校验逻辑匹配
            ('access_account_page', "可访问管理后台"),
            ('view_external', "可以查看外部客户"),

            ('system_settings', "系统设置"),  # 一级权限

            ('system_settings.group_rights', "组权分配"),  # 二级权限
            # ('system_settings.group_rights.add', "新增组权"),  # 三级权限
            # ('system_settings.group_rights.delete', "删除组权"),  # 三级权限
            # ('system_settings.group_rights.edit', "编辑组权"),  # 三级权限
            # ('system_settings.group_rights.view', "查询组权"),  # 三级权限

            ('system_settings.user_manage', "用户管理"),  # 二级权限
            ('system_settings.user_manage.add', "新增用户"),  # 三级权限
            ('system_settings.user_manage.delete', "删除用户"),  # 三级权限
            ('system_settings.user_manage.edit', "编辑用户"),  # 三级权限
            ('system_settings.user_manage.identityRole', "身份角色"),  # 三级权限
            # ('system_settings.user_manage.view', "查询用户"),  # 三级权限
            ('system_settings.user_manage.password', "修改密码"),  # 三级权限

            ('system_settings.permission', "权限管理"),  # 二级权限
            # ('system_settings.permission.add', "新增权限"),  # 三级权限
            # ('system_settings.permission.delete', "删除权限"),  # 三级权限
            # ('system_settings.permission.edit', "编辑权限"),  # 三级权限
            # ('system_settings.permission.view', "查询权限"),  # 三级权限

            ('E-ecom', "电商管理"),  # 一级权限

            ('E-ecom.banners', "横幅管理"),  # 二级权限
            ('E-ecom.banners.add', "新增横幅"),  # 三级权限
            ('E-ecom.banners.delete', "删除横幅"),  # 三级权限
            ('E-ecom.banners.edit', "编辑横幅"),  # 三级权限
            ('E-ecom.banners.view', "查询横幅"),  # 三级权限

            ('E-ecom.special', "特价管理"),  # 二级权限
            ('E-ecom.special.add', "新增特价"),  # 三级权限
            ('E-ecom.special.delete', "删除特价"),  # 三级权限
            ('E-ecom.special.edit', "编辑特价"),  # 三级权限
            ('E-ecom.special.view', "查询特价"),  # 三级权限

            ('E-ecom.goods', "商品管理"),  # 二级权限
            ('E-ecom.goods.add', "新增商品"),  # 三级权限
            ('E-ecom.goods.delete', "删除商品"),  # 三级权限
            ('E-ecom.goods.edit', "编辑商品"),  # 三级权限
            ('E-ecom.goods.view', "查询商品"),  # 三级权限

            ('E-ecom.order', "订单管理"),  # 二级权限
            ('E-ecom.order.add', "新增订单"),  # 三级权限
            ('E-ecom.order.delete', "删除订单"),  # 三级权限
            ('E-ecom.order.edit', "编辑订单"),  # 三级权限
            ('E-ecom.order.view', "查询订单"),  # 三级权限

            ('E-ecom.category', "分类管理"),  # 二级权限
            ('E-ecom.category.add', "新增分类"),  # 三级权限
            ('E-ecom.category.delete', "删除分类"),  # 三级权限
            ('E-ecom.category.edit', "编辑分类"),  # 三级权限
            ('E-ecom.category.view', "查询分类"),  # 三级权限

            ('E-ecom.report', "报表管理"),  # 二级权限
            ('E-ecom.report.add', "新增报表"),  # 三级权限
            ('E-ecom.report.delete', "删除报表"),  # 三级权限
            ('E-ecom.report.edit', "编辑报表"),  # 三级权限
            ('E-ecom.report.view', "查询报表"),  # 三级权限

            ('E-Entity', "实体管理"),  # 一级权限

            ('E-Entity.purchase', "进货管理"),  # 二级权限
            ('E-Entity.purchase.add', "新增进货"),  # 三级权限
            ('E-Entity.purchase.delete', "删除进货"),  # 三级权限
            ('E-Entity.purchase.edit', "编辑进货"),  # 三级权限
            ('E-Entity.purchase.view', "查询进货"),  # 三级权限

            ('E-Entity.sale', "销售管理"),  # 二级权限
            ('E-Entity.sale.add', "新增销售"),  # 三级权限
            ('E-Entity.sale.delete', "删除销售"),  # 三级权限
            ('E-Entity.sale.edit', "编辑销售"),  # 三级权限
            ('E-Entity.sale.view', "查询销售"),  # 三级权限

            ('E-Entity.report', "报表管理"),  # 二级权限
            ('E-Entity.report.add', "新增报表"),  # 三级权限
            ('E-Entity.report.delete', "删除报表"),  # 三级权限
            ('E-Entity.report.edit', "编辑报表"),  # 三级权限
            ('E-Entity.report.view', "查询报表"),  # 三级权限

            ('E-Entity.parameter', "参数管理"),  # 二级权限
            ('E-Entity.parameter.add', "新增参数"),  # 三级权限
            ('E-Entity.parameter.delete', "删除参数"),  # 三级权限
            ('E-Entity.parameter.edit', "编辑参数"),  # 三级权限
            ('E-Entity.parameter.view', "查询参数"),  # 三级权限
        ]

    def __str__(self):
        return f"{self.username} ({'员工' if self.is_staff else '顾客'})"

    def update_avatar(self, new_avatar):
        if self.avatar:  # 存在旧头像时删除
            self.avatar.delete(save=False)  # 删除物理文件
        self.avatar = new_avatar
        self.save()

    def has_super_perm(self):
        return self.groups.filter(name='超级权限').exists() or self.is_superuser


# class Category(models.Model):
#     """商品分类表"""
#     image = models.ImageField('分类图地址', upload_to=DatedUploadPath('products/category'), null=True, blank=True)
#     name = models.CharField(max_length=100, verbose_name="分类名称", unique=True)
#     parent = models.ForeignKey('self', null=True, blank=True,
#                                on_delete=models.CASCADE,
#                                related_name='children')  # 支持多级分类
#     description = models.TextField(blank=True, null=True, verbose_name="分类描述")
#     created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
#     updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
#
#     class Meta:
#         verbose_name = '商品分类'
#         verbose_name_plural = verbose_name
#         ordering = ['-created_at']
#
#     def __str__(self):
#         return self.name  # 返回分类名称，方便在后台显示


class Category(MPTTModel):
    name = models.CharField(max_length=50)
    parent = TreeForeignKey('self', on_delete=models.CASCADE,
                            null=True, blank=True,
                            related_name='children')

    class Meta:
        ordering = ['-id']  # 设置全局默认排序(django排序)
        constraints = [
            # 子分类在父分类下唯一
            models.UniqueConstraint(
                fields=['parent', 'name'],
                name='unique_subcategory_name'
            ),
            # 根分类全局唯一（使用条件约束）
            models.UniqueConstraint(
                fields=['name'],
                condition=Q(parent__isnull=True),
                name='unique_root_category'
            )
        ]

    class MPTTMeta:
        order_insertion_by = ['name']  # 可选排序(MPTT排序)

    def __str__(self):
        return self.name  # 返回名称，方便在后台显示


# #################  以下最新 #############
class Product(models.Model):  # 商品
    """商品基础信息"""
    # # 注意这里的related_name参数，它将反向查询的名称设置为products,比如在Category表中查询,可以用Category().products来查询有哪些商品
    # category = models.ManyToManyField(Category, related_name="products", verbose_name="分类")  # 外键关联分类表
    # category = models.ForeignKey(Category, related_name="products", on_delete=models.CASCADE, verbose_name="分类")
    # 替换为TreeManyToManyField, 注意字段名改为复数形式
    categories = TreeManyToManyField(Category, related_name="products", verbose_name="关联分类")
    name = models.CharField('商品名称', max_length=200)
    # main_image = models.ImageField('主图', upload_to=DatedUploadPath('products/main'))  # 用关联可以多张了
    video_url = models.FileField('视频', upload_to=DatedUploadPath('products/videos'),
                                 validators=[FileExtensionValidator(allowed_extensions=['mp4', 'mov', "avi", "wnv"])],
                                 blank=True, null=True
                                 )
    # 使用django-imagekit动态生成不同尺寸缩略图：因依赖pillow,所以需要向安装pip install Pillow,再pip install django-imagekit,settings.py中注册 'imagekit',
    thumbnail = ProcessedImageField(verbose_name='缩略图',
                                    upload_to=DatedUploadPath('products/thumbnails'),
                                    processors=[ResizeToFill(200, 200)],
                                    format='JPEG', blank=True
                                    )
    stock = models.PositiveIntegerField(default=0, verbose_name="总库存")
    price = models.DecimalField('售价', max_digits=10, decimal_places=2)
    original_price = models.DecimalField('原价', max_digits=10, decimal_places=2, null=True, blank=True)
    sales_total = models.IntegerField(default=0, verbose_name="销售总数量")  # 销售总数量

    details = models.JSONField(default=list, verbose_name="商品详情", blank=True,
                               null=True)  # 存 [{"材质":"xx"},{"产地":"xx"},{"颜色":"xx"},{"尺寸":"xx"}]等
    # description = models.TextField('商品描述', blank=True)
    description = RichTextUploadingField('商品描述', blank=True)
    is_active = models.BooleanField('上架状态', default=True)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)

    class Meta:
        verbose_name = '商品'
        verbose_name_plural = verbose_name
        ordering = ['-created_at']

    def __str__(self):
        return self.name  # 返回名称，方便在后台显示


class ProductImage(models.Model):  # 主图改为支持上传多张
    product = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
        related_name='main_images'  # 通过 product.main_images 访问关联图片
    )
    image = models.ImageField(
        '主图',
        upload_to=DatedUploadPath('products/main')  # 保持原路径规则
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = '商品主图'


# #####################  相关函数或类 ##########################
# 在保存产品实例之前从主图像自动生成缩略图的信号.
# @receiver(pre_save, sender=Product)
# def generate_thumbnail(sender, instance, *args, **kwargs):
#     if instance.main_image and not instance.thumbnail:
#         # 从主图像生成缩略图并将其保存到缩略图字段.
#         instance.thumbnail.save(
#             f"thumbnail_{instance.main_image.name}",
#             instance.main_image.file,
#             save=False,
#         )
# ############################################################

class Banner(models.Model):  # 轮播图
    title = models.CharField("标题", max_length=50)
    image = models.ImageField(
        '轮播图地址',
        upload_to=DatedUploadPath('products/banners'),
        null=True,
        blank=True
    )
    link = models.URLField("跳转链接", null=True, blank=True)  # 限制协议‌
    order = models.PositiveIntegerField("优先级", default=0)  # 控制显示顺序‌
    is_active = models.BooleanField("启用状态", default=True)  # 动态开关‌
    start_time = models.DateTimeField("生效时间", null=True, blank=True)  # 定时展示‌
    product = models.ForeignKey(
        'Product',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name="关联商品"
    )
    created_at = models.DateTimeField("创建时间", auto_now_add=True)
    updated_at = models.DateTimeField("更新时间", auto_now=True)
    meta_data = JSONField("元数据", default=dict, blank=True)  # 新增字段

    class Meta:
        verbose_name = "轮播图"  # 单数形式的显示名称
        verbose_name_plural = "轮播图"  # 复数形式的显示名称
        ordering = ['order']

    def __str__(self):
        return f"Banner {self.id} - {self.title}"

    @property
    def image_url(self):
        return self.image.url if self.image else ''

    def save(self, *args, **kwargs):
        # 自动设置默认标题
        if not self.title:
            self.title = f"横幅-{timezone.now().strftime('%Y%m%d')}"
        super().save(*args, **kwargs)


class SpecialOffer(models.Model):
    """ 特价商品表 """
    PROMO_TYPES = (
        ('flash_sale', '限时秒杀'),
        ('discount', '折扣促销'),
        ('group_buy', '拼团活动'),
        ('coupon', '优惠券关联')
    )

    product = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
        verbose_name="关联商品",
        related_name='special_offers'
    )

    # 价格相关
    promo_price = models.DecimalField(
        "促销价",
        max_digits=10,
        decimal_places=2,
        # validators=[MinValueValidator(0.01)]  # 防止0元
    )
    discount_rate = models.FloatField(
        "折扣率",
        validators=[MinValueValidator(0.1), MaxValueValidator(9.9)],  # 1折~9.9折
        null=True,
        blank=True
    )

    # 时间控制
    start_time = models.DateTimeField("开始时间")
    end_time = models.DateTimeField("结束时间")

    # 库存控制
    promo_stock = models.PositiveIntegerField(
        "促销库存",
        default=0,
        help_text="0表示使用商品原库存"
    )
    sold_count = models.PositiveIntegerField("已售数量", default=0, editable=False)

    # 展示控制
    is_active = models.BooleanField("启用状态", default=True)
    order_priority = models.IntegerField("排序优先级", default=0)
    promo_image = models.ImageField(
        "促销专属图",
        upload_to=DatedUploadPath('products/specials'),
        blank=True,
        help_text="留空则使用商品主图"
    )

    # 活动类型
    promo_type = models.CharField(
        "促销类型",
        max_length=20,
        choices=PROMO_TYPES,
        default='discount'
    )

    # 自动化字段
    created_at = models.DateTimeField("创建时间", auto_now_add=True)
    updated_at = models.DateTimeField("更新时间", auto_now=True)

    class Meta:
        indexes = [
            models.Index(fields=['start_time', 'end_time']),
            models.Index(fields=['is_active', 'order_priority']),
        ]
        ordering = ['-order_priority', '-created_at']

        verbose_name = "特价商品"  # 单数形式的显示名称
        verbose_name_plural = "特价商品"  # 复数形式的显示名称

    def clean(self):
        """ 数据验证 """
        from django.core.exceptions import ValidationError

        # 时间有效性
        if self.start_time >= self.end_time:
            raise ValidationError("结束时间必须晚于开始时间")

        # 价格保护
        if self.promo_price >= self.product.original_price:
            raise ValidationError("促销价必须低于原价")

    @property
    def remaining_stock(self):
        """ 实时剩余库存 """
        if self.promo_stock == 0:
            return self.product.stock - self.sold_count
        else:
            return self.promo_stock - self.sold_count

    def __str__(self):
        return f"{self.product.name} - {self.get_promo_type_display()}"


# 保存已经录入过的键值对:像"模号":"R37552","款式":"吊坠"等等(正在调试)
class ProductAttributeHistory(models.Model):
    """存储属性键的历史记录和最近值"""
    key = models.CharField('属性键', max_length=50, unique=True)
    last_value = models.CharField('最近值', max_length=255, blank=True)
    usage_count = models.PositiveIntegerField('使用次数', default=0)
    last_used = models.DateTimeField('最后使用时间', auto_now=True)

    class Meta:
        verbose_name = '属性历史记录'
        verbose_name_plural = verbose_name
        ordering = ['-usage_count', '-last_used']

    def __str__(self):
        return f"{self.key} ({self.usage_count})"


class AttributeCategory(models.Model):
    """属性分类（颜色/尺寸/版本等）"""
    name = models.CharField('属性类别', max_length=50, unique=True)
    display_order = models.PositiveIntegerField('显示顺序', default=0)

    class Meta:
        verbose_name = '属性分类'
        verbose_name_plural = verbose_name + '管理'
        ordering = ['display_order']


class AttributeNode(models.Model):
    """多级属性节点（支持无限层级）"""
    category = models.ForeignKey(AttributeCategory, on_delete=models.CASCADE, verbose_name='所属分类')
    parent = models.ForeignKey('self', on_delete=models.CASCADE,
                               null=True, blank=True,
                               related_name='children',
                               verbose_name='父级节点')
    value = models.CharField('属性值', max_length=100)
    code = models.CharField('编码', max_length=20, blank=True, help_text='用于SKU生成的唯一标识')
    is_leaf = models.BooleanField('末端节点', default=False, help_text='标记是否为最终可售属性节点')

    class Meta:
        verbose_name = '属性节点'
        unique_together = [('category', 'parent', 'value')]

    def save(self, *args, **kwargs):
        """自动维护末端节点标记"""
        self.is_leaf = not self.children.exists()
        super().save(*args, **kwargs)


class SKU(models.Model):
    # 新增预占库存字段
    reserved_stock = models.PositiveIntegerField('预占库存', default=0)

    """库存单元（末端节点组合）"""
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='skus', verbose_name='所属商品')
    attributes_hash = models.CharField(verbose_name='哈希值', max_length=64, unique=True)  # 属性组合哈希值

    attributes_json = models.TextField(verbose_name='动态用属性路径',
                                       help_text='格式：分类1:值1>分类2:值2>...')  # 原始属性结构存储  直接在这里存属性值:款式:款式1>尺寸:M码>新旧:新...
    # attribute_path = models.TextField('静态用属性路径', help_text='格式：分类1:值1>分类2:值2>...')

    price = models.DecimalField('售价', max_digits=10, decimal_places=2, )  # validators=[MinValueValidator(0.01)])
    original_price = models.DecimalField('原价', max_digits=10, decimal_places=2, null=True, blank=True)

    stock = models.PositiveIntegerField('库存', default=0)
    image = models.ImageField('专属图片', upload_to=DatedUploadPath('products/skus'), null=True, blank=True)
    is_active = models.BooleanField('可售状态', default=True)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)

    class Meta:
        verbose_name = '库存单元'
        unique_together = ('product', 'attributes_hash')
        ordering = ['-created_at']

    def __str__(self):
        return self.attributes_json  # 返回名称，方便在后台显示

    @transaction.atomic
    def reserve_stock(self, quantity):
        """预占库存"""
        if self.available_stock < quantity:
            raise ValidationError("库存不足")

        self.reserved_stock = F('reserved_stock') + quantity
        self.save(update_fields=['reserved_stock'])

    @property
    def available_stock(self):
        return self.stock - self.reserved_stock


User = UserInfo()


class Address(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='addresses')  # 关联用户
    receiver = models.CharField(max_length=20)  # 收货人姓名
    mobile = models.CharField(max_length=11)  # 手机号
    province = models.CharField(max_length=50)  # 省
    city = models.CharField(max_length=50)  # 市
    district = models.CharField(max_length=50)  # 区县
    detail = models.TextField()  # 详细地址
    is_default = models.BooleanField(default=False)  # 默认地址标识
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        # 联合唯一约束，彻底杜绝重复数据‌
        unique_together = [
            'user', 'receiver', 'mobile',
            'province', 'city', 'district', 'detail'
        ]
        verbose_name = '收货人地址'

    def __str__(self):
        return self.receiver


class SalesOrder(models.Model):
    """订单主表（存储订单基础信息）"""
    ORDER_STATUS_CHOICES = (
        ('unpaid', '待支付'),
        ('paid', '已支付'),
        ('shipped', '已发货'),
        ('evaluate', '待评价'),
        ('refunding', '退款中'),
        ('refunded', '已退款'),
        ('completed', '已完成'),
        ('cancelled', '已取消')
    )
    order_no = models.CharField('订单号', max_length=40, unique=True)
    user = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name='用户')  # 关联用户
    address = models.ForeignKey(Address, on_delete=models.SET_NULL, null=True)  # 关联地址
    total_amount = models.DecimalField('订单总额', max_digits=12, decimal_places=2)
    payment_time = models.DateTimeField('支付时间', null=True)
    order_sn = models.CharField('物流信息', max_length=64, unique=True)  # 被物流关联
    status = models.CharField('订单状态', max_length=20, choices=ORDER_STATUS_CHOICES, default='unpaid')
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)
    transaction_id = models.CharField(
        '支付平台交易号',
        max_length=64,  # 微信/支付宝交易号长度通常为28-32位，建议预留冗余
        unique=True,  # 强制唯一约束‌
        null=True,  # 允许未支付订单为空
        blank=True,
        db_index=True  # 提升查询性能‌
    )

    class Meta:
        verbose_name = '销售订单'
        indexes = [
            models.Index(fields=['order_no', 'user', 'created_at']),
            models.Index(fields=['status', 'payment_time'])  # status为前端带来的参数
        ]

    # 防重复通知处理
    def save(self, *args, **kwargs):
        if self.status == 1 and self._state.adding:
            raise ValueError('无法直接创建已付款订单')
        super().save(*args, **kwargs)

    @classmethod
    def update_from_wechat(cls, notify_data):  # 已在views.py中实现了,这里用不到了
        """处理微信支付回调"""
        # 验证签名（需实现 wechat_check_sign）
        if not wechat_check_sign(notify_data, settings.WECHAT_API3_KEY):
            raise ValueError('Invalid signature')

        order = cls.objects.get(out_trade_no=notify_data['out_trade_no'])
        if notify_data['return_code'] == 'SUCCESS':
            order.status = 1
            order.transaction_id = notify_data['transaction_id']
            order.payment_time = timezone.now()
            # 写入Redis缓存（有效期10分钟）
            redis = get_redis_connection('payment')
            redis.setex(f'payment:{order.id}', 600, 'PAID')
            order.save()
        return order


class OrderItem(models.Model):
    """订单明细表（存储商品购买细节）"""
    order = models.ForeignKey(SalesOrder, on_delete=models.CASCADE, related_name='items')
    sku = models.ForeignKey(SKU, on_delete=models.PROTECT, verbose_name='SKU')
    quantity = models.PositiveIntegerField('购买数量')
    unit_price = models.DecimalField('成交单价', max_digits=10, decimal_places=2)
    total_price = models.DecimalField('小计金额', max_digits=12, decimal_places=2)

    class Meta:
        verbose_name = '订单明细'


# class OrderStatusLog(models.Model):
#     """订单状态日志表（可选）"""
#     order = models.ForeignKey(SalesOrder, on_delete=models.CASCADE, related_name='logs')
#     from_status = models.CharField('原状态', max_length=20)
#     to_status = models.CharField('新状态', max_length=20)
#     operator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
#     created_at = models.DateTimeField('操作时间', auto_now_add=True)


# class AfterSalesService(models.Model):
#     """售后申请表"""
#     order = models.OneToOneField(SalesOrder, on_delete=models.PROTECT)
#     apply_type = models.CharField(max_length=20, choices=[('refund', '退货'), ('exchange', '换货')])
# 其他售后相关字段...

# #############  物流信息跟踪  #################
class LogisticsInfo(models.Model):
    order = models.ForeignKey('SalesOrder', on_delete=models.CASCADE, related_name='logistics')
    tracking_number = models.CharField(max_length=50)
    company_code = models.CharField(max_length=20)
    last_update = models.DateTimeField(auto_now=True)
    raw_data = models.JSONField()  # 存储原始物流数据

    class Meta:
        indexes = [
            models.Index(fields=['tracking_number']),
        ]
        verbose_name = '物流信息'


# ###################### 后端登录需补充模型:短信登录功能 ######################
# class SMSVerifyCode(models.Model):
#     phone = models.CharField(max_length=11)
#     code = models.CharField(max_length=6)
#     created = models.DateTimeField(auto_now_add=True)
#
#     class Meta:
#         verbose_name = '短信登录'
#
#     def is_expired(self):
#         return (timezone.now() - self.created).seconds > 300


# class PermissionGroup(models.Model):
#     """权限组"""
#     name = models.CharField(max_length=32)
#     code = models.CharField(max_length=32, unique=True)
#     permissions = models.ManyToManyField(Permission)
#
#     class Meta:
#         ordering = ['id']  # 按主键排序（或指定其他字段如 'name'）


# ###### 会话记录: 不好用,还未启用 ###################
class CustomSession(AbstractBaseSession):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,  # UserInfo
        on_delete=models.CASCADE,
        null=True,
        db_index=True,
        verbose_name="关联用户"
    )

    class Meta(AbstractBaseSession.Meta):
        verbose_name = "自定义会话"
        verbose_name_plural = "自定义会话"
